package Salesman.gui;

import Salesman.City;
import Salesman.Data.DataProvider;
import Salesman.Data.Icons.ImageIcon;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.painter.Painter;

public class SimulationMap extends MapKit {

    private Model model = new Model();
    private City startCity;
    Image startFlag, defaultFlag;

    public SimulationMap() {
        setAddressLocation(getCenter());
        getMainMap().setOverlayPainter(null);
        setZoom(11);
        startFlag = new ImageIcon("flag_red.png").getImage();
        defaultFlag = new ImageIcon("flag_blue.png").getImage();
        paint();
    }

    public City getStartCity() {
        return startCity;
    }

    public void setStartCity(City startCity) {
        this.startCity = startCity;
    }

    public void paint() {
        getMainMap().setOverlayPainter(new Painter<JXMapViewer>() {

            @Override
            public void paint(Graphics2D g, JXMapViewer t, int i, int i1) {
                try {
                    g = (Graphics2D) g.create();

                    Rectangle rect = getMainMap().getViewportBounds();
                    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g.translate(-rect.x, -rect.y);

                    List<City> cd = DataProvider.getInSimulationCities();

                    int start = 0;
                    if (startCity != null) {
                        start = cd.indexOf(startCity);
                    }


                    Point2D[] points = new Point2D[cd.size()];
                    for (int it = 0; it < cd.size(); it++) {
                        points[it] = getMainMap().getTileFactory().geoToPixel(
                                new GeoPosition(cd.get(it).getxPos(), cd.get(it).getyPos()), getMainMap().getZoom());
                    }
                    g.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_BUTT,
                            BasicStroke.JOIN_MITER));

                    if (getModel().size() > 1) {
                        Polygon poly = new Polygon();
                        for (City c : getModel()) {
                            int ci = cd.indexOf(c);
                            poly.addPoint((int) points[ci].getX(), (int) points[ci].getY());
                        }
                        g.setColor(Color.RED);
                        g.drawPolyline(poly.xpoints, poly.ypoints, getModel().size());

                    }

                    for (int it = 0; it < cd.size(); it++) {
                        Image img = defaultFlag;
                        if (it == start) {
                            img = startFlag;
                        }
                        g.drawImage(img, (int) points[it].getX() - 2, (int) points[it].getY() - img.getHeight(null) + 2, null);

                        g.setColor(Color.BLACK);
                        g.setFont(new Font("Arial", Font.BOLD, 12));
                        g.drawString(cd.get(it).getShortName(), (int) points[it].getX() - 4, (int) points[it].getY() + 13);
                    }
                    g.dispose();
                } catch (Exception excep) {
                }
            }
        });
    }

    private GeoPosition getCenter() {
        if (DataProvider.getCityData().isEmpty()) {
            return null;
        }

        double min_x = Double.POSITIVE_INFINITY, min_y = Double.POSITIVE_INFINITY;
        double max_x = Double.NEGATIVE_INFINITY, max_y = Double.NEGATIVE_INFINITY;

        for (City c : DataProvider.getCityData()) {
            min_x = Math.min(c.getxPos(), min_x);
            min_y = Math.min(c.getyPos(), min_y);
            max_x = Math.max(c.getxPos(), max_x);
            max_y = Math.max(c.getyPos(), max_y);
        }
        return new GeoPosition((min_x + max_x) / 2, (min_y + max_y) / 2);
    }

    public Model getModel() {
        return model;
    }

    public void setModel(Collection<City> model) {
        this.model = new Model();
        this.model.addAll(model);
        paint();
    }

    public class Model extends ArrayList<City> {

        @Override
        public boolean add(City e) {
            boolean add = super.add(e);
            paint();
            return add;
        }

        @Override
        public void add(int index, City element) {
            super.add(index, element);
            paint();
        }

        @Override
        public void clear() {
            super.clear();
            paint();
        }

        @Override
        public boolean addAll(Collection<? extends City> c) {
            boolean add = super.addAll(c);
            paint();
            return add;
        }

        @Override
        public boolean addAll(int index, Collection<? extends City> c) {
            boolean add = super.addAll(index, c);
            paint();
            return add;
        }

        @Override
        public boolean remove(Object o) {
            boolean remove = super.remove(o);
            paint();
            return remove;
        }

        @Override
        public City remove(int index) {
            City city = super.remove(index);
            paint();
            return city;
        }

        @Override
        public City set(int index, City element) {
            City city = super.set(index, element);
            paint();
            return city;
        }

        @Override
        public City get(int index) {
            return super.get(index % size());
        }
    }
}
